"""
内容提取模块 (Content Extractor)

从 semanticTree 和 interactionContext 中提取页面内容和交互目标。
Stage 2: 深度内容提取
"""

import re
from typing import Dict, Any, List, Optional
from html.parser import HTMLParser


class SemanticTreeParser(HTMLParser):
    """
    解析 semanticTree 字符串（简化的 HTML）

    semanticTree 格式示例:
    <body node-id="n_0">
        <main node-id="n_1">
            <div node-id="n_2">Hello World</div>
        </main>
    </body>
    """

    def __init__(self):
        super().__init__()
        self.nodes = {}  # node-id -> node info
        self.current_path = []  # 当前节点路径
        self.current_node_id = None
        self.current_tag = None
        self.current_attrs = {}
        self.text_buffer = []

    def handle_starttag(self, tag, attrs):
        """处理开始标签"""
        attrs_dict = dict(attrs)
        node_id = attrs_dict.get('node-id')

        self.current_tag = tag
        self.current_node_id = node_id
        self.current_attrs = attrs_dict

        if node_id:
            self.nodes[node_id] = {
                'tag': tag,
                'attrs': attrs_dict,
                'text': '',
                'children': [],
                'parent': self.current_path[-1] if self.current_path else None,
                'path': list(self.current_path) + [node_id]
            }

            # 更新父节点的 children
            if self.current_path:
                parent_id = self.current_path[-1]
                if parent_id in self.nodes:
                    self.nodes[parent_id]['children'].append(node_id)

            self.current_path.append(node_id)

    def handle_endtag(self, tag):
        """处理结束标签"""
        if self.current_path and self.text_buffer:
            # 将累积的文本分配给当前节点
            node_id = self.current_path[-1]
            if node_id in self.nodes:
                text = ''.join(self.text_buffer).strip()
                if text:
                    self.nodes[node_id]['text'] = text
            self.text_buffer = []

        if self.current_path:
            self.current_path.pop()

    def handle_data(self, data):
        """处理文本数据"""
        data = data.strip()
        if data:
            self.text_buffer.append(data)


class ContentExtractor:
    """内容提取器"""

    # 噪音标签（通常不包含主要内容）
    NOISE_TAGS = {'nav', 'aside', 'footer', 'header', 'script', 'style', 'noscript'}

    # 主内容标签（通常包含主要内容）
    CONTENT_TAGS = {'main', 'article', 'section', 'div', 'p', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6'}

    # 噪音关键词（class/id 属性中常见的噪音）
    NOISE_KEYWORDS = ['ad', 'banner', 'footer', 'nav', 'sidebar', 'cookie', 'popup', 'modal']

    def __init__(self):
        """初始化内容提取器"""
        pass

    def extract_page_content(self, event: Dict[str, Any], max_length: int = 3000) -> Dict[str, Any]:
        """
        从事件中提取页面主要内容

        Args:
            event: 事件数据
            max_length: 最大提取长度（字符数），用于控制 Token 消耗

        Returns:
            {
                'url': '页面 URL',
                'title': '页面标题',
                'main_content': '主要内容文本',
                'content_length': 内容长度,
                'interaction_target': '交互目标信息（如果有）',
                'metadata': {
                    'has_semantic_tree': True/False,
                    'node_count': 节点数量,
                    'extracted_nodes': 提取的节点数量
                }
            }
        """
        url = event.get('url', '')
        title = event.get('title', '')

        # 获取 semanticTree
        global_structure = event.get('globalStructure', {})
        semantic_tree_str = global_structure.get('semanticTree', '')

        if not semantic_tree_str:
            return {
                'url': url,
                'title': title,
                'main_content': '',
                'content_length': 0,
                'interaction_target': None,
                'metadata': {
                    'has_semantic_tree': False,
                    'node_count': 0,
                    'extracted_nodes': 0
                }
            }

        # 解析 semanticTree
        parser = SemanticTreeParser()
        try:
            parser.feed(semantic_tree_str)
        except Exception as e:
            return {
                'url': url,
                'title': title,
                'main_content': f'[解析失败: {e}]',
                'content_length': 0,
                'interaction_target': None,
                'metadata': {
                    'has_semantic_tree': True,
                    'node_count': 0,
                    'extracted_nodes': 0,
                    'parse_error': str(e)
                }
            }

        nodes = parser.nodes

        # 提取主要内容
        main_content_parts = []
        extracted_nodes = []

        for node_id, node_info in nodes.items():
            # 过滤噪音
            if self._is_noise_node(node_info):
                continue

            # 提取文本
            text = node_info.get('text', '').strip()
            if text and len(text) > 10:  # 至少10个字符
                main_content_parts.append(text)
                extracted_nodes.append(node_id)

                # 控制总长度
                if len(' '.join(main_content_parts)) >= max_length:
                    break

        # 合并文本
        main_content = ' '.join(main_content_parts)
        if len(main_content) > max_length:
            main_content = main_content[:max_length] + '...'

        # 提取交互目标
        interaction_target = self._extract_interaction_target(event, nodes)

        return {
            'url': url,
            'title': title,
            'main_content': main_content,
            'content_length': len(main_content),
            'interaction_target': interaction_target,
            'metadata': {
                'has_semantic_tree': True,
                'node_count': len(nodes),
                'extracted_nodes': len(extracted_nodes)
            }
        }

    def _is_noise_node(self, node_info: Dict[str, Any]) -> bool:
        """
        判断节点是否为噪音

        Args:
            node_info: 节点信息

        Returns:
            True 如果是噪音节点
        """
        tag = node_info.get('tag', '')
        attrs = node_info.get('attrs', {})

        # 1. 标签过滤
        if tag in self.NOISE_TAGS:
            return True

        # 2. class/id 过滤
        class_attr = attrs.get('class', '').lower()
        id_attr = attrs.get('id', '').lower()

        for keyword in self.NOISE_KEYWORDS:
            if keyword in class_attr or keyword in id_attr:
                return True

        return False

    def _extract_interaction_target(
        self,
        event: Dict[str, Any],
        nodes: Dict[str, Any]
    ) -> Optional[Dict[str, Any]]:
        """
        提取交互目标元素信息

        Args:
            event: 事件数据
            nodes: 解析后的节点字典

        Returns:
            交互目标信息，如果无法提取则返回 None
        """
        interaction_context = event.get('interactionContext', {})
        if not interaction_context:
            return None

        target_node_id = interaction_context.get('targetNodeId')
        if not target_node_id or target_node_id not in nodes:
            return None

        target_node = nodes[target_node_id]

        # 提取目标元素信息
        target_info = {
            'node_id': target_node_id,
            'tag': target_node.get('tag', ''),
            'text': target_node.get('text', ''),
            'selector': interaction_context.get('selector', ''),
        }

        # 尝试获取上下文（父节点和兄弟节点的文本）
        parent_id = target_node.get('parent')
        if parent_id and parent_id in nodes:
            parent_node = nodes[parent_id]
            target_info['context'] = {
                'parent_tag': parent_node.get('tag', ''),
                'parent_text': parent_node.get('text', '')[:200]  # 限制长度
            }

        return target_info

    def extract_interaction_summary(self, events: List[Dict[str, Any]]) -> Dict[str, Any]:
        """
        从一组事件中提取交互摘要

        Args:
            events: 事件列表（通常是同一个 URL 的事件）

        Returns:
            {
                'url': 'URL',
                'title': '标题',
                'page_content': '页面主要内容',
                'interactions': [
                    {
                        'event_type': '事件类型',
                        'target': '交互目标信息',
                        'timestamp': 时间戳
                    },
                    ...
                ],
                'interaction_count': 交互次数
            }
        """
        if not events:
            return {}

        # 使用最后一个事件的页面内容（通常最完整）
        last_event = events[-1]
        page_content = self.extract_page_content(last_event, max_length=2000)

        # 提取所有交互
        interactions = []
        for event in events:
            event_type = event.get('eventType', 'unknown')
            timestamp = event.get('timestamp', 0)

            # 提取交互目标（简化版，不需要完整解析）
            interaction_context = event.get('interactionContext', {})
            target_node_id = interaction_context.get('targetNodeId')
            selector = interaction_context.get('selector', '')

            interactions.append({
                'event_type': event_type,
                'target_node_id': target_node_id,
                'selector': selector,
                'timestamp': timestamp
            })

        return {
            'url': page_content['url'],
            'title': page_content['title'],
            'page_content': page_content['main_content'],
            'content_length': page_content['content_length'],
            'interactions': interactions,
            'interaction_count': len(interactions),
            'metadata': page_content['metadata']
        }
